home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / stdwin / Ports / mac / scroll.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-03-26  |  14.9 KB  |  677 lines  |  [TEXT/????]

  1. /*
  2. This code is somehow broken.
  3. If I click a few times on an arrow of the scroll bar the cursor freezes.
  4. Other forms of scrolling don't have this problem.  WHAT'S WRONG?!?!?!
  5. */
  6.  
  7. /* MAC STDWIN -- SCROLLING. */
  8.  
  9. /* All non-public functions here assume the current grafport is set */
  10.  
  11. /* XXX The contents of this file should be organized more top-down */
  12.  
  13. #include "macwin.h"
  14. #ifdef MPW
  15. #include <Events.h>
  16. #endif
  17.  
  18. /* I am using the fact here that the scroll bars of an inactive window
  19.    are invisible:
  20.    when a window's origin or its document size changes while it isn't the
  21.    active window, its controls get their new values but aren't redrawn. */
  22.  
  23. /* Key repeat constants in low memory (set by the Control Panel),
  24.    in ticks (used here to control the continuous scrolling speed). */
  25.  
  26. #define KeyThresh    (* (short*)0x18e)    /* Delay until repeat starts */
  27. #define KeyRepThresh    (* (short*)0x190)    /* Repeat rate */
  28.  
  29. #define JURJENBARPROC 48 /* CDEF id for Jurjen's proportional scrollbar */
  30.  
  31. STATIC void setscrollbarvalues _ARGS((WINDOW *win));
  32. STATIC void usescrollbarvalues _ARGS((WINDOW *win));
  33. STATIC void sizescrollbars _ARGS((WINDOW *win));
  34. STATIC int calcneworigin _ARGS((int, int, int, int, int));
  35. STATIC void calcbar _ARGS((ControlHandle bar,
  36.     int org, int size, int begin, int end));
  37. STATIC void setbar _ARGS((ControlHandle bar, int winsize, int val, int max));
  38. STATIC void deltabar _ARGS((ControlHandle bar, int delta));
  39. STATIC void showbar _ARGS((ControlHandle bar));
  40. STATIC void hidebar _ARGS((ControlHandle bar));
  41. STATIC void movebar _ARGS((ControlHandle bar,
  42.     int left, int top, int right, int bottom));
  43. void _wfixorigin _ARGS((WINDOW *));
  44.  
  45. void
  46. wsetorigin(win, orgh, orgv)
  47.     WINDOW *win;
  48.     int orgh, orgv;
  49. {
  50.     Rect r;
  51.     
  52.     /* XXX wsetorigin is currently the only routine that allows
  53.        the application to show bits outside the document.
  54.        Is even this desirable? */
  55.     
  56.     CLIPMIN(orgh, 0);
  57.     CLIPMIN(orgv, 0);
  58.     getwinrect(win, &r);
  59.     orgh -= LSLOP;
  60.     if (orgh != win->orgh || orgv != win->orgv) {
  61.         SetPort(win->w);
  62.         scrollby(win, &r, win->orgh - orgh, win->orgv - orgv);
  63.         win->orgh= orgh;
  64.         win->orgv= orgv;
  65.         setscrollbarvalues(win);
  66.     }
  67. }
  68.  
  69. void
  70. wgetorigin(win, ph, pv)
  71.     WINDOW *win;
  72.     int *ph, *pv;
  73. {
  74.     *ph = win->orgh + LSLOP;
  75.     *pv = win->orgv;
  76. }
  77.  
  78. void
  79. wshow(win, left, top, right, bottom)
  80.     WINDOW *win;
  81.     int left, top, right, bottom;
  82. {
  83.     int orgh, orgv;
  84.     int winwidth, winheight;
  85.     int docwidth, docheight;
  86.     
  87.     /* Calls to wshow while the mouse is down are ignored,
  88.        because they tend to mess up auto-scrolling.
  89.        I presume it's harmless (even the right thing to do),
  90.        since wshow is usually called to make sure the object
  91.        being selected is visible, which isn't a problem while
  92.        the user is busy pointing at it.
  93.        The check must be here, not in wsetorigin, because
  94.        the latter is used internally by the auto-scroll code! */
  95.     if (_wm_down)
  96.         return;
  97.     
  98.     /* The code below is generic for all versions of stdwin */
  99.     
  100.     wgetorigin(win, &orgh, &orgv);
  101.     wgetwinsize(win, &winwidth, &winheight);
  102.     wgetdocsize(win, &docwidth, &docheight);
  103.     
  104.     orgh = calcneworigin(orgh, left, right, winwidth, docwidth);
  105.     orgv = calcneworigin(orgv, top, bottom, winheight, docheight);
  106.     
  107.     wsetorigin(win, orgh, orgv);
  108. }
  109.  
  110. /* Subroutine for wshow to calculate new origin in h or v direction */
  111.  
  112. static int
  113. calcneworigin(org, low, high, winsize, docsize)
  114.     int org, low, high, winsize, docsize;
  115. {
  116.     if (docsize <= 0)
  117.         return org;
  118.     
  119.     /* Ignore requests to show bits outside doc */
  120.     /* XXX Is this necessary? */
  121.     CLIPMIN(low, 0);
  122.     CLIPMAX(high, docsize);
  123.     
  124.     /* Ignore requests for empty range */
  125.     /* XXX Is this what we want? */
  126.     if (high <= low)
  127.         return org;
  128.     
  129.     if (org <= low && high <= org + winsize)
  130.         return org;
  131.     
  132.     if (high - low > winsize) {    /* Range too big for window */
  133.         
  134.         /* Don't scroll if at least 1/3 of the window is in range */
  135.         /* XXX 1/3 is an arbitrary number! */
  136.         if (low <= org + winsize*2/3 && high >= org + winsize/3)
  137.             return org;
  138.         
  139.         /* Center the end of the range that's closest to the window */
  140.         if (low - org >= org + winsize - high) {
  141.             org = low - winsize/2;
  142.             CLIPMIN(org, 0);
  143.             return org;
  144.         }
  145.         else {
  146.             org = high - winsize/2;
  147.             CLIPMAX(org, docsize);
  148.             CLIPMIN(org, 0);
  149.             return org;
  150.         }
  151.     }
  152.     
  153.     /* The whole range will fit */
  154.     
  155.     /* See if it makes sense to scroll less than the window size */
  156.     if (low < org) {
  157.         if (org - low < winsize)
  158.             return low;
  159.     }
  160.     else if (high > org + winsize) {
  161.         if (high - (org + winsize) < winsize)
  162.             return high - winsize;
  163.     }
  164.     
  165.     /* Would have to scroll at least winsize -- center the range */
  166.     org = (low + high - winsize) / 2;
  167.     
  168.     /* Make sure we stay within the document */
  169.     CLIPMIN(org, 0);
  170.     CLIPMAX(org, docsize);
  171.     
  172.     return org;
  173. }
  174.  
  175. void
  176. wsetdocsize(win, docwidth, docheight)
  177.     WINDOW *win;
  178.     int docwidth, docheight;
  179. {
  180.     CLIPMIN(docwidth, 0);
  181.     CLIPMIN(docheight, 0);
  182.     if (docwidth == win->docwidth && docheight == win->docheight)
  183.         return;
  184.     win->docwidth= docwidth;
  185.     win->docheight= docheight;
  186.     SetPort(win->w);
  187.     setscrollbarvalues(win);
  188.     _wfixorigin(win);
  189.     
  190.     /* Make the zoomed window size the full document size,
  191.        or the full screen size if the document is bigger. */
  192.     
  193.     if (((WindowPeek)(win->w))->dataHandle != NULL) {
  194.         WStateData *data = (WStateData *)
  195.             *((WindowPeek)(win->w))->dataHandle;
  196.         if (data != NULL) {
  197.             if (docwidth > 0) {
  198.                 data->stdState.right =
  199.                     data->stdState.left
  200.                     + LSLOP + docwidth + RSLOP;
  201.                 if (win->vbar != NULL)
  202.                     data->stdState.right += BAR;
  203.             }
  204.             else
  205.                 data->stdState.right = 0x7fff;
  206.             CLIPMAX(data->stdState.right,
  207.                 screen->portRect.right-3);
  208.             if (win->hbar != NULL) {
  209.                 CLIPMIN(data->stdState.right, 5*BAR);
  210.             }
  211.             if (docheight > 0) {
  212.                 data->stdState.bottom =
  213.                     data->stdState.top + docheight;
  214.                 if (win->hbar != NULL)
  215.                     data->stdState.bottom += BAR;
  216.             }
  217.             else
  218.                 data->stdState.bottom = 0x7fff;
  219.             CLIPMAX(data->stdState.bottom,
  220.                 screen->portRect.bottom-3);
  221.             if (win->vbar != NULL) {
  222.                 CLIPMIN(data->stdState.bottom, 5*BAR);
  223.             }
  224.         }
  225.     }
  226. }
  227.  
  228. void
  229. wgetdocsize(win, pwidth, pheight)
  230.     WINDOW *win;
  231.     int *pwidth, *pheight;
  232. {
  233.     *pwidth = win->docwidth;
  234.     *pheight = win->docheight;
  235. }
  236.  
  237. /* Fix the window's origin after a document or window resize.
  238.    (Also used from do_size() in event.c) */
  239.  
  240. void
  241. _wfixorigin(win)
  242.     WINDOW *win;
  243. {
  244.     int orgh, orgv;
  245.     int winwidth, winheight;
  246.     int docwidth, docheight;
  247.     wgetorigin(win, &orgh, &orgv);
  248.     wgetwinsize(win, &winwidth, &winheight);
  249.     wgetdocsize(win, &docwidth, &docheight);
  250.     
  251.     /* XXX Do we really want this?
  252.        This means that in a text edit window, if you are focused
  253.        at the bottom, every line deletion causes a scroll.
  254.        Oh well, I suppose that text edit windows could fix
  255.        their document size to include some blank lines at the
  256.        end...
  257.     */
  258.     
  259.     CLIPMAX(orgh, docwidth - winwidth);
  260.     CLIPMIN(orgh, 0);
  261.     CLIPMAX(orgv, docheight - winheight);
  262.     CLIPMIN(orgv, 0);
  263.     wsetorigin(win, orgh, orgv);
  264. }
  265.  
  266. /* do_scroll is called from event.c when a click in a scroll bar
  267.    is detected */
  268.  
  269. STATIC pascal trackbar(ControlHandle bar, short pcode); /* Forward */
  270.  
  271. static WINDOW *scrollwin;    /* The window (needed by 'trackbar') */
  272. static int scrollstep;        /* By how much we scroll */
  273. static long deadline;        /* When the next step may happen */
  274.  
  275. void
  276. do_scroll(pwhere, win, bar, pcode)
  277.     Point *pwhere;
  278.     WINDOW *win;
  279.     ControlHandle bar;
  280.     int pcode;
  281. {
  282.     int step, page;
  283.     ProcPtr action;
  284.     int width, height;
  285.     
  286.     if (bar == NULL)
  287.         return;
  288.     
  289.     wgetwinsize(win, &width, &height);
  290.     
  291.     if (bar == win->hbar) {
  292.         step= width / 20;
  293.         CLIPMIN(step, 1);
  294.         page= width / 2;
  295.     }
  296.     else if (bar == win->vbar) {
  297.         step= wlineheight(); /* Should use current win's */
  298.         page= height - step;
  299.     }
  300.     else
  301.         return;
  302.     
  303.     page= (page/step) * step; /* Round down to multiple of step */
  304.     action= trackbar;
  305.     scrollwin= win;
  306.     
  307.     switch (pcode) {
  308.     case inUpButton:
  309.         scrollstep= -step;
  310.         break;
  311.     case inDownButton:
  312.         scrollstep= step;
  313.         break;
  314.     case inPageUp:
  315.         scrollstep= -page;
  316.         break;
  317.     case inPageDown:
  318.         scrollstep= page;
  319.         break;
  320.     default:
  321.         action= NULL;
  322.         break;
  323.     }
  324.     
  325.     deadline= 0;
  326.     if (TrackControl(bar, PASSPOINT *pwhere, action) == inThumb)
  327.         usescrollbarvalues(win);
  328.     
  329.     SetPort(win->w); /*  THIS IS NEEDED!!! */
  330. }
  331.  
  332. static pascal
  333. trackbar(bar, pcode)
  334.     ControlHandle bar;
  335.     short pcode;
  336. {
  337.     long now= TickCount();
  338.     if (now >= deadline && pcode != 0) {
  339.          deltabar(bar, scrollstep);
  340.         usescrollbarvalues(scrollwin);
  341.         wupdate(scrollwin);
  342.         if (deadline == 0 && KeyThresh > KeyRepThresh)
  343.             deadline= now + KeyThresh;
  344.             /* Longer delay first time */
  345.         else
  346.             deadline= now + KeyRepThresh;
  347.     }
  348. }
  349.  
  350. /* Automatic scrolling when the mouse is pressed and moved outside
  351.    the application panel. */
  352.  
  353. void
  354. autoscroll(win, h, v)
  355.     WINDOW *win;
  356.     int h, v; /* Mouse location in local coordinates */
  357. {
  358.     Rect r;
  359.     int dh= 0, dv= 0;
  360.     
  361.     getwinrect(win, &r);
  362.     if (h < r.left)
  363.         dh= h - r.left;
  364.     else if (h > r.right)
  365.         dh= h - r.right;
  366.     if (v < r.top)
  367.         dv= v - r.top;
  368.     else if (v > r.bottom)
  369.         dv= v - r.bottom;
  370.     if (dh != 0 || dv != 0) {
  371.         /* NOTE: assuming current grafport is win->w */
  372.         deltabar(win->hbar, dh);
  373.         deltabar(win->vbar, dv);
  374.         usescrollbarvalues(win);
  375.     }
  376. }
  377.  
  378. /* Alternative scrolling: Option-click produces a 'hand' cursor
  379.    and allows scrolling like in MacPaint.  Called from event.c. */
  380.  
  381. void
  382. dragscroll(win, h, v, constrained)
  383.     WINDOW *win;
  384.     int h, v;
  385.     int constrained;
  386. {
  387.     int do_h= !constrained, do_v= !constrained;
  388.     
  389.     while (StillDown()) {
  390.         Point mouse;
  391.         SetPort(win->w);
  392.         GetMouse(&mouse);
  393.         if (constrained) {
  394.             int ah= ABS(h - mouse.h);
  395.             int av= ABS(v - mouse.v);
  396.             if (ABS(ah - av) < 2)
  397.                 continue;
  398.             if (ah > av)
  399.                 do_h= TRUE;
  400.             else
  401.                 do_v= TRUE;
  402.             constrained= FALSE;
  403.         }
  404.         if (do_h)
  405.             deltabar(win->hbar, h - mouse.h);
  406.         if (do_v)
  407.             deltabar(win->vbar, v - mouse.v);
  408.         usescrollbarvalues(win);
  409.         wupdate(win);
  410.         h= mouse.h;
  411.         v= mouse.v;
  412.     }
  413. }
  414.  
  415. #ifdef JURJENBARPROC
  416. static int cdefexists _ARGS((int));
  417. static int
  418. cdefexists(id)
  419.     int id;
  420. {
  421.     return GetResource('CDEF', id/16) != NULL;
  422. }
  423. #endif
  424.  
  425. void
  426. makescrollbars(win, hor, ver)
  427.     WINDOW *win;
  428.     /*bool*/int hor, ver;
  429. {
  430.     Rect r;
  431.     int id= scrollBarProc;
  432.     
  433.     /* The scroll bars are initially created at a dummy location,
  434.        and then moved to their proper location.
  435.        They are not displayed here;
  436.        that's done only when an activate event arrives. */
  437.     
  438. #ifdef JURJENBARPROC
  439.     /* If Jurjen's proportional scroll bar exists, use it.
  440.        (For the vertical bar only -- it doesn't understand
  441.        about horizontal bars...) */
  442.     if (cdefexists(JURJENBARPROC))
  443.         id= JURJENBARPROC;
  444. #endif JURJENBARPROC
  445.  
  446.     SetRect(&r, 0, 0, 1, 1); /* Dummy rectangle */
  447.     if (hor)
  448.         win->hbar= NewControl(win->w,
  449.             &r, "", false, 0, 0, 0, scrollBarProc, 0L);
  450.     if (ver)
  451.         win->vbar= NewControl(win->w,
  452.             &r, "", false, 0, 0, 0, id, 0L);
  453.     sizescrollbars(win);
  454. }
  455.  
  456. void
  457. showscrollbars(win)
  458.     WINDOW *win;
  459. {
  460.     _wgrowicon(win);
  461.     showbar(win->hbar);
  462.     showbar(win->vbar);
  463. }
  464.  
  465. void
  466. hidescrollbars(win)
  467.     WINDOW *win;
  468. {
  469.     hidebar(win->hbar);
  470.     hidebar(win->vbar);
  471. }
  472.  
  473. void
  474. movescrollbars(win)
  475.     WINDOW *win;
  476. {
  477.     hidescrollbars(win);
  478.     sizescrollbars(win);
  479.     showscrollbars(win);
  480. }
  481.  
  482. static void
  483. sizescrollbars(win)
  484.     WINDOW *win;
  485. {
  486.     Rect r;
  487.     
  488.     /* This must only be called while the scroll bars are invisible. */
  489.     
  490.     r = win->w->portRect;
  491.     r.left = r.right - BAR;
  492.     r.top--;
  493.     r.bottom -= BAR-1;
  494.     r.right++;
  495.     movebar(win->vbar, r.left, r.top, r.right, r.bottom);
  496.     
  497.     r = win->w->portRect;
  498.     r.left--;
  499.     r.top = r.bottom - BAR;
  500.     r.right -= BAR-1;
  501.     r.bottom++;
  502.     movebar(win->hbar, r.left, r.top, r.right, r.bottom);
  503.     
  504.     setscrollbarvalues(win);
  505. }
  506.  
  507. static void
  508. setscrollbarvalues(win)
  509.     WINDOW *win;
  510. {
  511.     Rect r;
  512.     
  513.     getwinrect(win, &r);
  514.     calcbar(win->hbar,
  515.         win->orgh, win->docwidth, LSLOP, r.right - r.left - RSLOP);
  516.     calcbar(win->vbar,
  517.         win->orgv, win->docheight, 0, r.bottom - r.top);
  518.     if (win == active) {
  519.         /* XXX Should only draw those controls that have changed. */
  520.         DrawControls(win->w);
  521.         valid_border(win->w);
  522.     }
  523. }
  524.  
  525. /*
  526.  * Calculate (and set!) the new value of a scroll bar.
  527.  * Parameters (all pertaining to either h or v): 
  528.  * org:     origin of window (win->orgh or win->orgv)
  529.  * size:    extent of document (win->docwidth or win->docheight)
  530.  * begin:    position of document origin if bar is at its beginning
  531.  * end:        position of document end if bar is at its end
  532.  * Situation sketch:
  533.  *                0    begin                          end  winwidth
  534.  *                +====+==============================+====+
  535.  *                     +--------------------------------------------------+
  536.  * +--------------------------------------------------+
  537.  * Window shown on top; min document position in the middle;
  538.  * max document position below.  Org is (begin of win) - (begin of doc).
  539.  */
  540.  
  541. static void
  542. calcbar(bar, org, size, begin, end)
  543.     ControlHandle bar;
  544.     int org, size;
  545.     int begin, end;
  546. {
  547.     int range;
  548.     
  549.     if (bar == NULL)
  550.         return;
  551.     
  552.     /* For the caller it's easier to remember to pass win->org{h,v};
  553.        but for our calculations it's easier to have the sign reversed! */
  554.     org= -org;
  555.     CLIPMIN(begin, org);
  556.     CLIPMIN(size, 0);
  557.     CLIPMAX(end, org + size);
  558.     range = size - (end - begin);
  559.     CLIPMIN(range, 0);
  560.     setbar(bar, end - begin, begin - org, range);
  561. }
  562.  
  563. static void
  564. usescrollbarvalues(win)
  565.     WINDOW *win;
  566. {
  567.     int orgh = 0;
  568.     int orgv = 0;
  569.     if (win->hbar != NULL)
  570.         orgh = GetCtlValue(win->hbar) - GetCtlMin(win->hbar);
  571.     if (win->vbar != NULL)
  572.         orgv = GetCtlValue(win->vbar) - GetCtlMin(win->vbar);
  573.     wsetorigin(win, orgh, orgv);
  574.     /* Implies setscrollbarvalues! */
  575. }
  576.  
  577. static void
  578. setbar(bar, winsize, val, max)
  579.     ControlHandle bar;
  580.     int winsize, val, max;
  581. {
  582.     if (bar != NULL) {
  583.         ControlPtr p= *bar;
  584.         if (max < 0)
  585.             max= 0;
  586.         if (val > max)
  587.             val= max;
  588.         if (val < 0)
  589.             val= 0;
  590.         p->contrlMin= winsize;
  591.         p->contrlValue= val + winsize;
  592.         p->contrlMax= max + winsize;
  593.         /* Must be drawn by DrawControls or ShowControl. */
  594.     }
  595. }
  596.  
  597. static void
  598. deltabar(bar, delta)
  599.     ControlHandle bar;
  600.     int delta;
  601. {
  602.     int min, val, max, newval;
  603.     
  604.     if (bar == NULL)
  605.         return;
  606.     min = GetCtlMin(bar);
  607.     val = GetCtlValue(bar);
  608.     max = GetCtlMax(bar);
  609.     newval = val + delta;
  610.     
  611.     if (newval > max)
  612.         newval= max;
  613.     if (newval < min)
  614.         newval= min;
  615.     if (newval != val)
  616.         SetCtlValue(bar, newval);
  617. }
  618.  
  619. static void
  620. showbar(bar)
  621.     ControlHandle bar;
  622. {
  623.     if (bar != NULL)
  624.         ShowControl(bar);
  625. }
  626.  
  627. static void
  628. hidebar(bar)
  629.     ControlHandle bar;
  630. {
  631.     if (bar != NULL)
  632.         HideControl(bar);
  633. }
  634.  
  635. static void
  636. movebar(bar, left, top, right, bottom)
  637.     ControlHandle bar;
  638.     int left, top, right, bottom;
  639. {
  640.     if (bar != NULL) {
  641.         /* This works best while the scroll bar is invisible. */
  642.         MoveControl(bar, left, top);
  643.         SizeControl(bar, right-left, bottom-top);
  644.     }
  645. }
  646.  
  647. void
  648. _wgrowicon(win)
  649.     WINDOW *win;
  650. {
  651.     Rect r;
  652.     
  653.     /* If there are no scroll bars, there is no room to draw the
  654.        grow icon; the entire window belongs to the application.
  655.        However, clicks in the bottom right corner will still be
  656.        intercepted by the window manager. */
  657.     
  658.     if (win->hbar == NULL && win->vbar == NULL)
  659.         return;
  660.     
  661.     /* Clip the drawing of DrawGrowIcon to the scroll bars present. */
  662.     
  663.     r= win->w->portRect;
  664.     if (win->hbar == NULL)
  665.         r.left = r.right - BAR;
  666.     if (win->vbar == NULL)
  667.         r.top = r.bottom - BAR;
  668.     ClipRect(&r);
  669.     
  670.     DrawGrowIcon(win->w);
  671.     
  672.     /* Reset clipping */
  673.     
  674.     SetRect(&r, -32000, -32000, 32000, 32000);
  675.     ClipRect(&r);
  676. }
  677.